package io.plus.user_interface.common.protocol;

import drds.common.Constants;
import io.plus.interactive.AioDecodeException;
import io.plus.interactive.AsynchronousSocketChannelContext;
import io.plus.user_interface.common.Status;
import io.plus.user_interface.common.packet.Command;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;

@Slf4j
public class Decoder {


    public static PacketImpl decode(ByteBuffer byteBuffer, AsynchronousSocketChannelContext asynchronousSocketChannelContext) throws AioDecodeException {
        //校验协议头
        if (!isHeaderLength(byteBuffer)) {
            return null;
        }
        //获取第一个字节协议版本号;
        byte version = byteBuffer.get();
        if (version != ProtocolConstants.VERSION) {
            throw new AioDecodeException(Status.C10013.getMark());
        }
        //标志位
        byte maskByte = byteBuffer.get();
        Integer synSeq = 0;
        //同步发送;
        if (PacketImpl.decodeHasSynSeq(maskByte)) {
            synSeq = byteBuffer.getInt();
        }
        //cmd命令码
        byte commandByte = byteBuffer.get();
        if (Command.forNumber(commandByte) == null) {
            throw new AioDecodeException(Status.C10014.getMark());
        }
        int bodyLength = byteBuffer.getInt();
        //数据不正确，则抛出AioDecodeException异常
        if (bodyLength < 0) {
            throw new AioDecodeException("bodyLength [" + bodyLength + "] is not right, remote:" + asynchronousSocketChannelContext.getClientNode());
        }
        int readableLength = byteBuffer.limit() - byteBuffer.position();
        int validateBodyLen = readableLength - bodyLength;
        // 不够消息体长度(剩下的buffer组不了消息体)
        if (validateBodyLen < 0) {
            return null;
        }
        byte[] bodyBytes = new byte[bodyLength];
        byteBuffer.get(bodyBytes, 0, bodyLength);
        log.info("TCP解码成功...");
        //byteBuffer的总长度是 = 1byte协议版本号+1byte消息标志位+4byte同步序列号(如果是同步发送则多4byte同步序列号,否则无4byte序列号)+1byte命令码+4byte消息的长度+消息体的长度
        PacketImpl packet = new PacketImpl(Command.forNumber(commandByte), bodyBytes);
        packet.setVersion(version);
        packet.setMask(maskByte);
        //同步发送设置同步序列号
        if (synSeq > 0) {
            packet.setSynchronismSerialNumber(synSeq);
            try {
                asynchronousSocketChannelContext.getClientConfiguration().getAioHandler().handler(asynchronousSocketChannelContext, packet);
            } catch (Exception e) {
                log.error("同步发送解码调用handler异常!" + e);
            }
        }
        return packet;
    }

    /**
     * 判断是否符合协议头长度
     */
    private static boolean isHeaderLength(ByteBuffer buffer) {
        int readableLength = buffer.limit() - buffer.position();
        if (readableLength == 0) {
            return false;
        }
        //协议头索引;
        int index = buffer.position();
        try {
            //获取第一个字节协议版本号;
            buffer.get(index);
            index++;
            //标志位
            byte maskByte = buffer.get(index);
            //同步发送;
            if (PacketImpl.decodeHasSynSeq(maskByte)) {
                index += 4;
            }
            index++;
            //cmd命令码
            buffer.get(index);
            index++;
            //消息体长度
            buffer.getInt(index);
            index += 4;
            if (Constants.developMode) {
                log.debug("index:" + index);
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
